from typing import Any

from zkl_pyutils_registries import UNSET

from zkl_pyutils_serialization.basics import get_context_tag_value
from zkl_pyutils_serialization.convert import registry
from zkl_pyutils_serialization.convertors.common import PyObjectFormat
from zkl_pyutils_serialization.tags import DstFormat, DstTypehint, SrcFormat, SrcType
from .format import JsonValueFormat

NoneType = type(None)


@registry.register({SrcFormat: PyObjectFormat, DstFormat: JsonValueFormat, SrcType: int, DstTypehint: int})
@registry.register({SrcFormat: JsonValueFormat, DstFormat: PyObjectFormat, SrcType: int, DstTypehint: int})
def int_convertor(value: int) -> int:
    return value


@registry.register({SrcFormat: PyObjectFormat, DstFormat: JsonValueFormat, SrcType: float, DstTypehint: int})
@registry.register({SrcFormat: JsonValueFormat, DstFormat: PyObjectFormat, SrcType: float, DstTypehint: int})
def int_convertor_casting(value: float) -> int:
    value_casted = int(value)
    if value_casted == value:
        return value_casted
    raise NotImplementedError


@registry.register({SrcFormat: PyObjectFormat, DstFormat: JsonValueFormat, SrcType: int})
@registry.register({SrcFormat: JsonValueFormat, DstFormat: PyObjectFormat, SrcType: int})
def int_convertor_passive(value: int) -> int:
    if get_context_tag_value(DstTypehint) not in (UNSET, Any):
        raise NotImplementedError
    return value


@registry.register({SrcFormat: PyObjectFormat, DstFormat: JsonValueFormat, SrcType: float, DstTypehint: float})
@registry.register({SrcFormat: JsonValueFormat, DstFormat: PyObjectFormat, SrcType: float, DstTypehint: float})
def float_convertor(value: float) -> float:
    return value


@registry.register({SrcFormat: PyObjectFormat, DstFormat: JsonValueFormat, SrcType: int, DstTypehint: float})
@registry.register({SrcFormat: JsonValueFormat, DstFormat: PyObjectFormat, SrcType: int, DstTypehint: float})
def float_convertor_casting(value: int) -> float:
    return float(value)


@registry.register({SrcFormat: PyObjectFormat, DstFormat: JsonValueFormat, SrcType: float})
@registry.register({SrcFormat: JsonValueFormat, DstFormat: PyObjectFormat, SrcType: float})
def float_convertor_passive(value: float) -> float:
    if get_context_tag_value(DstTypehint) not in (UNSET, Any):
        raise NotImplementedError
    return value


@registry.register({SrcFormat: JsonValueFormat, DstFormat: PyObjectFormat, SrcType: str, DstTypehint: str})
@registry.register({SrcFormat: PyObjectFormat, DstFormat: JsonValueFormat, SrcType: str, DstTypehint: str})
def str_convertor(value: str) -> str:
    return value


@registry.register({SrcFormat: PyObjectFormat, DstFormat: JsonValueFormat, SrcType: str})
@registry.register({SrcFormat: JsonValueFormat, DstFormat: PyObjectFormat, SrcType: str})
def str_convertor_passive(value: str) -> str:
    if get_context_tag_value(DstTypehint) not in (UNSET, Any):
        raise NotImplementedError
    return value


@registry.register({SrcFormat: PyObjectFormat, DstFormat: JsonValueFormat, SrcType: bool, DstTypehint: bool})
@registry.register({SrcFormat: JsonValueFormat, DstFormat: PyObjectFormat, SrcType: bool, DstTypehint: bool})
def bool_convertor(value: bool) -> bool:
    return value


@registry.register({SrcFormat: PyObjectFormat, DstFormat: JsonValueFormat, SrcType: bool})
@registry.register({SrcFormat: JsonValueFormat, DstFormat: PyObjectFormat, SrcType: bool})
def bool_convertor_passive(value: bool) -> bool:
    if get_context_tag_value(DstTypehint) not in (UNSET, Any):
        raise NotImplementedError
    return value


@registry.register({SrcFormat: PyObjectFormat, DstFormat: JsonValueFormat, SrcType: NoneType, DstTypehint: NoneType})
@registry.register({SrcFormat: JsonValueFormat, DstFormat: PyObjectFormat, SrcType: NoneType, DstTypehint: NoneType})
def none_convertor(value: None) -> None:
    return value


@registry.register({SrcFormat: PyObjectFormat, DstFormat: JsonValueFormat, SrcType: NoneType})
@registry.register({SrcFormat: JsonValueFormat, DstFormat: PyObjectFormat, SrcType: NoneType})
def none_convertor_passive(value: None) -> None:
    if get_context_tag_value(DstTypehint) not in (UNSET, Any):
        raise NotImplementedError
    return value
